package com.ikdong.toodle.util;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.google.gson.internal.StringMap;
import com.ikdong.toodle.dao.TaskDAO;
import com.ikdong.toodle.exception.TDException;
import com.ikdong.toodle.model.Account;
import com.ikdong.toodle.model.BasicTask;
import com.ikdong.toodle.model.Task;
import android.content.Context;
import android.util.Log;

public class TaskManager {
	private String userId;
	private String key;
	private TaskDAO dao;
	private AccountManager accountManager;
	
	public TaskManager(Context context){
		accountManager = new AccountManager(context);
		userId = accountManager.getAccount().getUserid();
		key = new AuthManager(context).getKey();
		dao = new TaskDAO(context);
	}
	
	public List<Task> get(){
		List<Task> tasks = new ArrayList<Task>();
		tasks.addAll(dao.getTaskBySyncStatus(0,null,userId, Constant.STATUS_SYNC_ADD,Constant.STATUS_SYNC_DONE,Constant.STATUS_SYNC_MODIFY)); 
		return tasks;
	}
	
	public List<Task> get(String oderItem,long oderBy){
		List<Task> tasks = new ArrayList<Task>();
		tasks.addAll(dao.getTaskBySyncStatus(oderBy,oderItem,userId, Constant.STATUS_SYNC_ADD,Constant.STATUS_SYNC_DONE,Constant.STATUS_SYNC_MODIFY)); 
		return tasks;
	}
	
	public Task get(long id){
		return dao.get(id);
	}
	
	public boolean update(Task task){
		return dao.update(task,Constant.STATUS_SYNC_MODIFY);
	}
	
	public boolean updateFolderChange(long oldId, long newId){
		return dao.updateFolder(oldId,newId);
	}
	
	public boolean updateContextChange(long oldId, long newId){
		return dao.updateContext(oldId,newId);
	}
	
	public boolean updateGoalChange(long oldId, long newId){
		return dao.updateGoal(oldId,newId);
	}
	
	public boolean add(Task task){
		return dao.add(task, userId, Constant.STATUS_SYNC_ADD);
	}
	
	public List<Task> getCompleted(){
		return dao.getTaskByCompleted(userId);
	}
	
	public List<Task> getOnline(Long modbefore, Long modafter, Long comp, Long id, Long start, Long num){
		List<Task> tasks = new ArrayList<Task>();
		Map<String, String> params = new HashMap<String, String>();
		params.put("key", key);
		params.put("fields", "folder,context,goal,location,tag,startdate,duedate,duedatemod,starttime,duetime,remind,repeat,status,star,priority,length,timer,added,note,parent,children,order");
		if(modbefore!=null){
			params.put("modbefore", modbefore.toString());
		}
		if(modafter!=null){
			params.put("modafter", modafter.toString());
		}
		if(comp!=null){
			params.put("comp", comp.toString());
		}
		if(id!=null){
			params.put("id", id.toString());
		}
		if(start!=null){
			params.put("start", start.toString());
		}
		if(num!=null){
			params.put("num", num.toString());
		}
		tasks.addAll(ToodleHttpClient.getTasks(params));
		return tasks;
	}
	
	private List<Task> getDeletedTasks(Long modafter){
		List<Task> tasks = new ArrayList<Task>();Map<String, String> params = new HashMap<String, String>();
		params.put("key", key);
		if(modafter!=null){
			tasks.addAll(ToodleHttpClient.getDeletedTasks(params));
		}
		
		return tasks;
	}
	
	public void addTask(List<Task> tasks){
		for(Task task : tasks){
			Log.d(Constant.TAG, "TaskManager.addTask - name: "+task.getTitle());
			dao.add(task, userId, Constant.STATUS_SYNC_DONE);
		}
	}
	
	public void delete(long id){
		dao.delete(id);
	}
	
	public boolean deleteByStatus(long id){
		return dao.updateStatus(id, Constant.STATUS_SYNC_DELETE);
	}
	
	public void deleteAll(){
		dao.delete();
	}
	
	public boolean updateTaskComp(long id,long value){
		Task task = new Task();
		task.setId(Long.valueOf(id));
		task.setCompleted(Long.valueOf(value));
		
		return dao.update(task,Constant.STATUS_SYNC_MODIFY);
	}
	
	public boolean updateTaskStar(long id,long value){
		Task task = new Task();
		task.setId(Long.valueOf(id));
		task.setStar(Long.valueOf(value));
		
		return dao.update(task,Constant.STATUS_SYNC_MODIFY);
	}
	
	private boolean addOnline(List<Task> tasks){
		boolean flag = true;
		try{
			List<BasicTask> mTasks = new ArrayList<BasicTask>();
			List<Long> ids = new ArrayList<Long>();
			for(BasicTask t : tasks){
				mTasks.add(t);
				ids.add(t.getId());
				t.setId(null);
			}
			List<Task> rtasks = ToodleHttpClient.addTask(key, mTasks);
			for(int i =0; i<ids.size(); i++){
				dao.replaceId(ids.get(i), rtasks.get(i).getId());
			}
		}catch(Exception e){
			Log.e(Constant.TAG, "TaskManager.addOnline()", e);
			flag = false;
		}
		return flag;
	}
	
	public void editOnline(List<Task> tasks) throws Exception{
		boolean flag = true;
		try{
			List<BasicTask> btasks = new ArrayList<BasicTask>();
			for(Task t : tasks){
				btasks.add((BasicTask) t);
			}
			List<Task> rtasks = ToodleHttpClient.editTask(key, btasks);
			for(Task task : rtasks){
				dao.update(task,Constant.STATUS_SYNC_DONE);
			}
		}catch(Exception e){
			Log.e(Constant.TAG, "TaskManager.editOnline()", e);
			flag = false;
		}
		
		if(!flag)
			throw new TDException("100","Unknown Error.");
	}
	
	@SuppressWarnings("rawtypes")
	public boolean deleteOnline(List<Task> tasks){
		boolean flag = true;
		try{
			List<String> ids = new ArrayList<String>();
			for(Task task : tasks){
				ids.add(task.getId().toString());
			}
			List<StringMap> rids = ToodleHttpClient.deleteTask(key, ids);
			for(StringMap sid : rids){
				if(sid.get("id")!=null)
					dao.delete(Long.valueOf(sid.get("id").toString()));
			}
		}catch(Exception e){
			Log.e(Constant.TAG, "TaskManager.editOnline()", e);
			flag = false;
		}
		return flag;
	}
	
	private void syncNewTasks() throws Exception{
		boolean flag = true;
		List<Task> tasks = dao.getTaskBySyncStatus(0,null,userId, Constant.STATUS_SYNC_ADD);
		if(tasks.size()>0)
			flag = this.addOnline(tasks);
		if(!flag)
			throw new TDException("100","Unknown Error.");
	}
	
	private void syncDeletedTasks() throws Exception{
		boolean flag = true;
		List<Task> tasks = dao.getTaskBySyncStatus(0,null,userId, Constant.STATUS_SYNC_DELETE);
		if(tasks.size()>0)
			flag = this.deleteOnline(tasks);
		if(!flag)
			throw new TDException("100","Unknown Error.");
	}
	
	private void syncOnlineTasks() throws Exception{
		Account account = accountManager.getAccount();
		//get edit tasks
		List<Task> tasks = this.getOnline(null, account.getLastedit_task(), Constant.TASK_UNCOMPLETED, null, Long.valueOf(0), null);
		Log.d(Constant.TAG, "get online tasks: "+tasks.size());
		List<Long> ids = new ArrayList<Long>();
		for(Task oTask : tasks){
			Task lTask = dao.get(oTask.getId());
			if(lTask==null){
				dao.add(oTask, userId, Constant.STATUS_SYNC_DONE);
			}else if(!lTask.getModified().equals(oTask.getModified())){
				dao.delete(lTask.getId());
				dao.add(oTask, userId, Constant.STATUS_SYNC_DONE);
			}
			
			ids.add(oTask.getId());
		}
		
		// get deleted tasks
		List<Task> dTasks = getDeletedTasks(account.getLastdelete_task());		
		if(dTasks.size()>0)
			dao.delete(dTasks);
		
		//get modified tasks
		List<Task> mTasks = dao.getTaskBySyncStatus(0,null,userId, Constant.STATUS_SYNC_MODIFY);
		if(mTasks.size()>0)
			editOnline(mTasks);
	}
	
	public void sync() throws Exception{
		syncNewTasks();
		syncDeletedTasks();
		syncOnlineTasks();
	}
}
